﻿#light

module AstOperations

open Might.Infrastructure.ModelicaDOM
open Might.Infrastructure.ModelicaDOM.Expressions
open System.Collections.ObjectModel
open System.Collections.Generic
open System

open AstTypes

let GLOBAL_ROOT_NAME = "GLOBAL_ROOT"

let splitQualifiedName(name:string) =
    String.split ['.'] name


let rec concatQualifiedName(name: string list) =    
    let partialName = match name with
                        | h::t -> h + "."  + concatQualifiedName t
                        | [] -> ""
    partialName.TrimEnd([|'.'|])

// converts name obtained during parsing to string
// first reverts the list (because name is captured in reverse order)  
// then concatenates it
let convertNameToString(nameList) =
    List.rev nameList |> concatQualifiedName

let createComponentReference(parts:ComponentReferenceParts list) = 
        List.rev parts
        
let createStringReference(ref:ComponentReference) = 
    let rec createStringReferenceEx(refParts:ComponentReferenceParts list) = 
        match refParts with
        | h :: t -> 
            match h with
            | ComponentReferenceParts.Name name ->
                name + "." + createStringReferenceEx(t)
            | _ ->
                createStringReferenceEx(t)
        | [] -> String.Empty
    let refName = createStringReferenceEx(ref._parts)
    refName.TrimEnd([|'.'|])
   
let flattenComponent( decls:Declaration list,typeName:string, prefix:TypePrefix ) =
    let compType = new Class();
    compType._name <- typeName    
    let createComponent(decl:Declaration) =
        let cmp = new Component();
        cmp._name <- decl._name                        
        cmp._type <- compType
        cmp._modification <- decl._modification._classModification
        cmp._assignedValue <- decl._modification._assignedValue
        cmp._comment <- decl._comment
        ComponentDef(cmp)
    List.map createComponent decls

let rec stringFromComponentReference(compRef: ComponentReferenceParts list) = 
    let rec stringFromComponentReferenceRec(ref: ComponentReferenceParts list) = 
        match ref with
        | h :: t ->
            match h with
            | Name n ->
                n + "." + stringFromComponentReference(t)
            | ArrayIndex _ -> 
                stringFromComponentReference(t)
        | [] -> String.Empty    
    (stringFromComponentReferenceRec(compRef)).TrimEnd([|'.'|])
    
let resolveModificationElementList(modElList: ModificationElement list, clsModif: ClassModification) =
    let duplicationCounter = ref 1
    let resolveModificationElement(modEl: ModificationElement) =
        match modEl with        
        | ClassRedefinitionDef clsRed ->
            clsModif._classRedef.Add(clsRed._class._name,clsRed)
        | ComponentModificationDef compMod ->
            let refName = stringFromComponentReference(compMod._compReference._parts)
            try                
                clsModif._compModif.Add( refName,compMod)
            with
            | _ ->
                //System.Console.WriteLine("Chybkaaaaaaaaaaa********************************")
                clsModif._compModif.Add( refName + "*" + (!duplicationCounter).ToString(),compMod)
                incr duplicationCounter
                
        | ComponentRedefinitionDef compRed ->
            clsModif._compRedef.Add(compRed._component._name,compRed);
        | _ -> ()
    List.iter resolveModificationElement modElList    

let resolveElementSection(cls:Class, eList:ElementList) =
    let rec resolveElementList(elemList: Element list) =    
        match elemList with
        | h::t ->
            match h with
                | ComponentDef comp -> 
                    comp._visibility <- eList._visibility
                    cls._components.Add(comp._name,comp)
                | ClassDef nstCls -> 
                    nstCls._visibility <- eList._visibility                    
                    cls._nestedClasses.Add(nstCls._name,nstCls)
                    nstCls._enclosingClass <- Some(cls)
                | ImportDef import ->                                 
                    match eList._visibility with
                    | Visibility.Protected -> cls._protectedImportedNames <- import :: cls._protectedImportedNames
                    | _ -> cls._publicImportedNames <- import :: cls._publicImportedNames
                | ExtendDef extend ->
                    match eList._visibility with
                    | Visibility.Protected -> cls._protectedInheritsFrom.Add(extend._baseClassName,extend)
                    | _ -> cls._publicInheritsFrom.Add(extend._baseClassName,extend)
                | AnnotationDef annot -> cls._annotations.Add(annot)
            resolveElementList(t)        
        | [] -> ()
    let res = resolveElementList(eList._elementList)
    res
     
let resolveEquationSection(cls:Class,eqSec:EquationSection) =    
    for sec in eqSec._eqList do
        if eqSec._initial = true then
            match sec with
            | EquationOrAnnotation.Annot annot ->
                cls._initialEquationsAnnotations <- annot :: cls._initialEquationsAnnotations
            | EquationOrAnnotation.Eq eq ->
                cls._initialEquations <- eq :: cls._initialEquations
        else
            match sec with
            | EquationOrAnnotation.Annot annot ->
                cls._initialEquationsAnnotations <- annot :: cls._equationsAnnotations
            | EquationOrAnnotation.Eq eq ->
                cls._equations <- eq :: cls._initialEquations

let rec filterComposition(cls:Class, comp:Composition) =
    match (List. rev comp) with
    | h::t -> match h with
                | ElementSection elSec -> resolveElementSection(cls,elSec)
                | EqSection eqSec -> resolveEquationSection(cls,eqSec) // unimplemented
                | AlgorithmSection AlgSec -> () // unimplemented
                | ExternalSection exSec -> () // unimplemented
              filterComposition(cls,t)
    | [] -> ()

